home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume2
/
unix
/
ls20.1
< prev
next >
Wrap
Internet Message Format
|
1988-12-12
|
61KB
Path: xanth!ames!mailrus!ulowell!page
From: page@swan.ulowell.edu (Bob Page)
Newsgroups: comp.sources.amiga
Subject: v02i097: ls - unix-like directory lister v2.0
Message-ID: <10673@swan.ulowell.edu>
Date: 12 Dec 88 22:05:59 GMT
Organization: University of Lowell, Computer Science Dept.
Lines: 2325
Approved: page@swan.ulowell.edu
Submitted-by: nop@cup.portal.com
Posting-number: Volume 2, Issue 97
Archive-name: unix/ls20.1
Here is a new version of Justin McCormick's "ls" program.
Hope the net enjoys the program -- I sure do!
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# c2.a
# ls.c
# ls.doc
# ls.h
# ls.lnk
# lssup.a
# makefile
# This archive created: Mon Dec 12 17:01:16 1988
cat << \SHAR_EOF > c2.a
*
* C initial startup procedure under AmigaDOS
*
* Use the following command line to make c.o
* asm -u -iINCLUDE: c.a
*
* Use the following command line to make cres.o
* asm -u -dRESIDENT -iINCLUDE: -ocres.o c.a
IDNT "c2.a"
OPTION L
LISTSYMS
BASEREG B
SMALLOBJ
OPTIMON
ADDSYM
DEBUG
* --------------------------------------------------------------------- *
* Macros:
* --------------------------------------------------------------------- *
SYS MACRO *
IFGT NARG-2
FAIL !!!
ENDC
IFEQ NARG-2
MOVE.L \2,a6
ENDC
JSR _LVO\1(a6)
ENDM
XLVO MACRO *
XREF _LVO\1
ENDM
* --------------------------------------------------------------------- *
* Equates:
* --------------------------------------------------------------------- *
RESIDENT EQU 1
MEMF_PUBLIC EQU $1
MEMF_CLEAR EQU $10000
MEMFLAGS EQU MEMF_CLEAR+MEMF_PUBLIC
AbsExecBase EQU $0004
cli_CommandName EQU $10
pr_CLI EQU $AC
pr_CurrentDir EQU $98
ThisTask EQU $114
_LVOCloseLibrary EQU $FE62
_LVOAllocMem EQU $FF3A
_LVOFreeMem EQU $FF2E
_LVOSetSignal EQU $FECE
_LVOOpenLibrary EQU $FDD8
XREF _DOSBase
XREF _LinkerDB ; linker defined base value
XREF __BSSBAS ; linker defined base of BSS
XREF __BSSLEN ; linker defined length of BSS
IFD RESIDENT
XREF _RESLEN
XREF _RESBASE
XREF _NEWDATAL
ENDC
XREF __main ; Name of C program to start with.
XREF _MemCleanup ; Free all allocated memory
XREF ___fpinit ; initialize floating point
XREF ___fpterm ; terminate floating point
* --------------------------------------------------------------------- *
SECTION TEXT,CODE
* --------------------------------------------------------------------- *
XDEF zzstart
zzstart:
move.l a0,a2 ; save command pointer
move.l d0,d2 ; and command length
lea _LinkerDB,a4 ; load base register
IFND RESIDENT
lea __BSSBAS,a3 ; get base of BSS
moveq #0,d1
move.l #__BSSLEN,d0 ; get length of BSS in longwords
bra.b clr_lp ; and clear for length given
clr_bss move.l d1,(a3)+
clr_lp dbf d0,clr_bss
ENDC
IFD RESIDENT
movea.l AbsExecBase,a6
movem.l d0-d1/a0-a2,-(sp)
sub.l #_RESBASE,a4
move.l #_RESLEN,d0
move.l #MEMFLAGS,d1
SYS AllocMem
tst.l d0
beq.w abort
move.l d0,a0
move.l d0,a2
;a2 now has difference
move.l d0,a1
move.l #_NEWDATAL,d0
;copy data over
cpy: move.l (a4)+,(a0)+
subq.l #1,d0
bne cpy
;a4 now points at number of relocs
move.l (a4)+,d0
reloc: beq.b nreloc
move.l a1,a0
add.l (a4)+,a0 ; a0 now has add of reloc
add.l (a0),a2
move.l a2,(a0)
move.l a1,a2 ; restore offset
subq.l #1,d0
bra reloc
nreloc: move.l a1,a4 ; set up new base register
add.l #_RESBASE,a4
movem.l (sp)+,d0-d1/a0-a2
ENDC
movea.l AbsExecBase,a6
move.l a6,_SysBase(a4)
move.l sp,__StackPtr(a4) ; Save stack ptr
clr.l _WBenchMsg(a4)
* get the address of our task
move.l ThisTask(a6),a3
*- clear any pending signals
moveq #0,d0
move.l #$00003000,d1
SYS SetSignal
* are we running as a son of Workbench?
move.l pr_CurrentDir(a3),_curdir(a4)
IFD WBENCH
tst.l pr_CLI(a3)
beq fromWorkbench
ENDC
*=======================================================================
*====== CLI Startup Code ===============================================
*=======================================================================
*
; Entry: d2 = command length
; a2 = Command pointer
fromCLI:
move.l sp,d0 ; get top of stack
sub.l 4(sp),d0 ; compute bottom
add.l #128,d0 ; allow for parms overflow
move.l d0,__base(a4) ; save for stack checking
* attempt to open DOS library:
bsr.w openDOS
* find command name:
move.l pr_CLI(a3),a0
add.l a0,a0 ; bcpl pointer conversion
add.l a0,a0
move.l cli_CommandName(a0),a1
add.l a1,a1 ; bcpl pointer conversion
add.l a1,a1
* collect parameters:
move.l d2,d0 ; get command line length
moveq.l #0,d1
move.b (a1)+,d1
move.l a1,__ProgramName(a4)
add.l d1,d0 ; add length of command name
addq.l #1,d0 ; allow for space after command
clr.w -(sp) ; set null terminator for command line
addq.l #1,d0 ; force to even number of bytes
andi.w #$fffe,d0 ; (round up)
sub.l d0,sp ; make room on stack for command line
subq.l #2,d0
clr.w 0(sp,d0)
* copy command line onto stack
move.l d2,d0 ; get command line length
subq.l #1,d0
add.l d1,d2
copy_line:
move.b 0(a2,d0.w),0(sp,d2.w) ; copy command line to stack
subq.l #1,d2
dbf d0,copy_line
move.b #' ',0(sp,d2.w) ; add space between command and parms
subq.l #1,d2
copy_cmd:
move.b 0(a1,d2.w),0(sp,d2.w) ; copy command name to stack
dbf d2,copy_cmd
move.l sp,a1
move.l a1,-(sp) ; push command line address
IFD WBENCH
bra main ; call C entrypoint
* --------------------------------------------------------------------- *
* Workbench Startup Code
* --------------------------------------------------------------------- *
fromWorkbench:
move.l TC_SPLOWER(a3),__base(a4) ; set base of stack
moveq #127,d0
addq.l #1,d0 ; Efficient way of getting in 128
add.l d0,__base(a4) ; allow for parms overflow
* open the DOS library:
bsr.w openDOS
* we are now set up. wait for a message from our starter
lea pr_MsgPort(a3),a0 ; our process base
SYS WaitPort
lea pr_MsgPort(a3),a0 ; our process base
SYS GetMsg
move.l d0,_WBenchMsg(a4)
move.l d0,-(sp)
move.l d0,a2 ; get first argument
move.l sm_ArgList(a2),d0
beq do_cons
move.l _DOSBase(a4),a6
move.l d0,a0
move.l wa_Lock(a0),d1
move.l d1,_curdir(a4)
SYS CurrentDir
do_cons:
move.l sm_ToolWindow(a2),d1 ; get the window argument
beq do_main
move.l #MODE_OLDFILE,d2
SYS Open
move.l d0,_stdin(a4)
beq do_main
lsl.l #2,d0
move.l d0,a0
move.l fh_Type(a0),pr_ConsoleTask(a3)
do_main:
move.l _WBenchMsg(a4),a0 ; get address of workbench message
move.l a0,-(sp) ; push argv
pea _NULL(a4) ; push argc
move.l sm_ArgList(a0),a0 ; get address of arguments
move.l wa_Name(a0),__ProgramName(a4) ; get name of program
ENDC
* --------------------------------------------------------------------- *
* Common CLI/WBENCH code
* --------------------------------------------------------------------- *
main:
IFD FLOAT
jsr ___fpinit(pc) ; Initialize floating point
ENDC
jsr __main(pc) ; call C entrypoint
moveq.l #0,d0 ; set successful status
bra.b exit2
XDEF _XCEXIT
_XCEXIT:
move.l 4(sp),d0 ; extract return code
XDEF xXCEXIT
xXCEXIT:
exit2:
IFD ERRTRAPS
move.l d0,-(sp)
move.l __ONEXIT(a4),d0 ; exit trap function?
beq.b exit3
move.l d0,a0
jsr (a0)
exit3:
ENDC
IFD MALLOC
jsr _MemCleanup(pc) ; cleanup leftover memory alloc.
ENDC
movea.l AbsExecBase,a6
move.l _DOSBase(a4),a1
SYS CloseLibrary ; close Dos library
IFD FLOAT
jsr ___fpterm(pc) ; clean up any floating point
ENDC
IFD WBENCH
done_1c:
* if we ran from CLI, skip workbench cleanup:
tst.l _WBenchMsg(a4)
beq exitToDOS
move.l _stdin(a4),d1
beq.b done_4
SYS Close
done_4:
* return the startup message to our parent
* we forbid so workbench can't UnLoadSeg() us
* before we are done:
movea.l AbsExecBase,a6
SYS Forbid
move.l _WBenchMsg(a4),a1
SYS ReplyMsg
ENDC
* this rts sends us back to DOS:
exitToDOS:
IFD RESIDENT
move.l #_RESLEN,d0
move.l a4,a1
sub.l #_RESBASE,a1
movea.l AbsExecBase,a6
SYS FreeMem
ENDC
move.l (sp)+,d0
movea.l __StackPtr(a4),sp ; restore stack ptr
XDEF xchkabort
xchkabort:
rts
IFD RESIDENT
abort:
movem.l (sp)+,d0-d1/a0-a2
rts
ENDC
* --------------------------------------------------------------------- *
noDOS:
moveq.l #100,d0
bra exit2
* --------------------------------------------------------------------- *
* Open the DOS library:
* --------------------------------------------------------------------- *
openDOS:
lea DOSName(pc),a1
moveq.l #0,d0
SYS OpenLibrary
move.l d0,_DOSBase(a4)
beq noDOS
rts
DOSName: dc.b 'dos.library',0
* --------------------------------------------------------------------- *
section __MERGED,BSS
* --------------------------------------------------------------------- *
XDEF _NULL,_SysBase,_WBenchMsg
XDEF _curdir,__mbase,__mnext,__msize,__tsize
XDEF __oserr,__OSERR
IFD FLOAT
XDEF __FPERR
XDEF __SIGFPE
ENDC
IFD ERRTRAPS
XDEF __ONERR,__ONEXIT,__ONBREAK
XDEF __SIGINT
ENDC
XDEF _stdin
XDEF __ProgramName,__StackPtr,__base
* --------------------------------------------------------------------- *
_NULL ds.l 1 ; Huh?
__base ds.l 1 ; base of stack
__mbase ds.l 1 ; base of memory pool
__mnext ds.l 1 ; next available memory location
__msize ds.l 1 ; size of memory pool
__tsize ds.l 1 ; total size?
__oserr
__OSERR ds.l 1
IFD FLOAT
__FPERR ds.l 1
__SIGFPE ds.l 1
ENDC
IFD ERRTRAPS
__SIGINT ds.l 1
__ONERR ds.l 1
__ONEXIT ds.l 1
__ONBREAK ds.l 1
ENDC
_curdir ds.l 1
_SysBase ds.l 1
_WBenchMsg ds.l 1
__StackPtr ds.l 1
_stdin ds.l 1
__ProgramName ds.l 1
* --------------------------------------------------------------------- *
END
* --------------------------------------------------------------------- *
SHAR_EOF
cat << \SHAR_EOF > ls.c
/* --------------------------------------------------------------------- *
LS.C -- an "improved" directory listing utility to replace the
AmigaDOS DIR and LIST commands.
V1.0 August 1986 Written from scratch by Justin V. McCormick.
V2.0 November 1988 Revised for Lattice 5.0 and made 1.3 compatible.
Notice:
This program is placed in the public domain with the understanding
that the author makes no claims or guarantees with regard to its
suitability for any given application, and that the author assumes no
responsibility for damages incurred by its usage. Any resemblance
of this program to any other program, either living or dead, is
purely coincidental.
Feel free to steal this code and make millions of dollars from its sale
or commercial use, but please give credit where credit is due.
Synopsis:
Features adaptive columnar listing, versatile sort options,
UNIX-style pattern matching, recursive subdirectory listing, etc!
Usage:
ls [options] [path1] [path2] ...
Options:
-? Help!
-c Show file comment info, -c implies -l
-d Show directory names only
-f Show filenames only
-l Long verbose listing showing filesizes and dates
-n No sort, just spit them out in the order ExNext() returns
-r Reverse sort direction
-s Sorted by size smallest to largest
-t Sorted by date oldest to newest
-R Recursive descent of subdirectories
All arguments are optional. Default is to give short columnar listing,
sorted alphabetically, using the current directory. Alphabetizing is case
insensitive.
Patterns may be matched in the given names, using the UNIX-style '*'
to wildcard any number of characters, and '?' to wildcard a single
character. If you need to specify a pathname with spaces in it like
"Wombat Soup", you need to put quotes around it. LS can process up to 30
separate pathname patterns in one command line.
Bugs:
Redirecting the shortlist output to PRT: gives undesirable results,
since I am using relative cursor positioning commands to format the
screen output. I thought about using an array to store a virtual
screen, but my primary goals were to keep the size down and display
speed at a maxiumum. Also, LS cannot pattern match devices (like "dh*:")
or support multiple levels of pattern matching (like "dh0:?/L*.info").
This would involve another level of recursion and groking the Device List.
Changes From 1.0 to 2.0:
o Source code prototyped, linted, traced, optimized, tweaked, etc.
o Made resident ("pseudo-pure") by linking with cres.o from LC 5.0.
o High-volume routines recoded in assembly (lssup.a).
o Now handles multiple paths/files on a command line, up to 30.
o New sort flags, including no sort.
o Enhanced wildcards, understands complex *.?*.* expressions now.
o More efficient ExNext() performance, less ram used for recursion.
o SIGBREAKF_CTRL_C signal (Ctrl-C) cleanly aborts at any point now.
o Command line parser handles quoted pathnames now (LC 5.0 benefit).
o Short listing finally auto-adjusts to new console window sizes!
o Pen color escape codes bypassed when redirecting long output.
o Sorting by size or date is also subsorted alphabetically now.
o Long listing shows new 1.3 file attributes, plus comment indicator.
o File dates are now in international format, YY-MM-DD.
o Fixed listings with files datestamped after 99-12-31 (overflow).
o Fixed listings with files datestamped before 78-01-01 (time < 0).
* --------------------------------------------------------------------- */
#include "ls.h"
/* Structure used to hold file info in a linked list */
struct FibEntry
{
struct FibEntry *NextFib;
struct FibEntry *LastFib;
struct FileInfoBlock *Fibp;
};
/* Externs from lssup.a */
/*lint +fva2 */
extern int __stdargs asprintf (char *, char *,...);
/*lint -fva2 */
extern __asm void SortFibs (R_D0 long, R_D1 long, R_A0 struct FibEntry *);
extern __stdargs long iswild (char *);
extern __stdargs long wildmatch (char *, char *);
extern __stdargs char *FibFileDate (struct DateStamp *);
extern __stdargs void GetWinBounds(long *, long *);
/* Local CODE */
struct FibEntry *GetDir (BPTR, struct FileInfoBlock *);
struct FibEntry *AllocFib (void);
void CleanUp (char *, long);
void ColorPen2 (void);
void CursorOff (void);
void CursorOn (void);
void DirIt (BPTR, char *);
void FreeAllFibs (struct FibEntry *);
void FreeFib (struct FibEntry *);
void LListDir (struct FibEntry *);
void LListEntry (struct FileInfoBlock *);
void LongList (long *, long *, struct FibEntry *);
void main (int, char **);
void PagePrompt (long);
void ResetPen (void);
void SListDir (struct FibEntry *);
void TestBreak (void);
void Usage (void);
void WCHR (char *);
void WSTR (char *);
BPTR Out = 0L;
BPTR In = 0L;
BPTR lockp = 0L;
struct FileInfoBlock *GFibp = 0L;
long BREAKFLAG = 0;
long CONSOLE = 0;
long dircount = 0;
long DIRFILEFLAG = 0;
long errstat = 0;
long filecount = 0;
long LISTALL = 0;
long LONGLIST = 0;
long maxnamlen = 0;
long NOSORTFLAG = 0;
long NOTEFLAG = 0;
long PATHNAMED = 0;
long REVFLAG = 0;
long sortkey = 0;
long WILDCARD = 0;
long CurWinRows = 20L;
long CurWinCols = 77L;
char filename[160];
char pattern[160];
char workstr[160];
static char Author[] = "\23333mLS 2.0\2330m by Justin V. McCormick 1988";
static char usage[] = "\nUsage: ls [-cdflnrstR] [path1] [path2] ...\n";
/* -------------------------------------------------------------------- */
void main (argc, argv)
int argc;
char **argv;
{
struct Process *procp;
long cnt, i;
if (argc == 0) /* son of Workbench -- no go! */
exit (0);
/* Grab FileHandles for input and output to console (or redirection file) */
In = Input ();
Out = Output ();
CONSOLE = (IsInteractive (Out) == 0L) ? 0L : 1L; /* Is this console output? */
/* Allocate a global FileInfoBlock for ExNext() */
if ( (GFibp = (struct FileInfoBlock *)AllocMem((long)sizeof(struct FileInfoBlock), MEMF_PUBLIC | MEMF_CLEAR)) == 0L)
CleanUp("No RAM?", 103L);
/* Parse command line arguments <ugh> */
cnt = 1;
if (argc >= 2)
{
if (argv[1][0] == '-')
{
cnt++;
for (i = strlen(argv[1]) - 1; i > 0; i--)
{
switch (argv[1][i])
{
case 'c':
LONGLIST = 1;
NOTEFLAG = 1;
break;
case 'd':
DIRFILEFLAG |= 1;
break;
case 'f':
DIRFILEFLAG |= 2;
break;
case 'l':
LONGLIST = 1;
break;
case 'n':
NOSORTFLAG = 1;
break;
case 'r':
REVFLAG = 1;
break;
case 's':
sortkey = 1;
break;
case 't':
sortkey = 2;
break;
case 'R':
LISTALL = 1;
break;
case '?':
Usage ();
break;
default:
(void) asprintf (workstr, "Unknown option \'%c\'\n", argv[1][i]);
WSTR (workstr);
Usage ();
break;
}
}
}
}
/* Clean up the state flags */
if ( (argc - cnt) > 1)
LISTALL |= 2;
if (DIRFILEFLAG == 0)
DIRFILEFLAG = 3;
/* Loop through the remaining args now */
do
{
PATHNAMED = 0;
if (cnt < argc)
{
(void) stpcpy (pattern, argv[cnt]);
PATHNAMED = 1;
}
if (PATHNAMED) /* If user specified a pathname */
{
WILDCARD = iswild (pattern); /* check for wildcards */
if (WILDCARD) /* If wildcards, separate */
{ /* pattern from pathname */
for (i = (strlen (pattern) - 1); i >= 0; i--)
{
if (pattern[i] == '/' || pattern[i] == ':')
{
(void) strncpy (filename, pattern, (UWORD) (i + 1));
filename[i + 2] = (BYTE) 0;
(void) stpcpy (workstr, &pattern[i + 1]);
(void) stpcpy (pattern, workstr);
break;
}
}
/* Disallow wildcards in pathname */
if (iswild (filename))
CleanUp ("Sorry, can't pattern match paths", 5L);
}
else /* No wildcards, use filename as is */
{
(void) stpcpy (filename, pattern);
}
/* If the user specified a pathname, try to grab a FileLock on it */
/* Discard trailing slash if silly Joe User put one there */
if (filename[1] != 0 && filename[strlen (filename) - 1] == '/')
filename[strlen (filename) - 1] = (BYTE) 0;
lockp = Lock (filename, ACCESS_READ);
if (!lockp) /* Can't Lock it! */
{
errstat = IoErr ();
(void) strcat (filename, " not found");
CleanUp (filename, (long)errstat);
}
}
else
{
/*
* If no filename was specified, steal Lock on current directory from
* CLI process task info. We durn well better get something useful back;
* we don't do any error checking on the stolen Lock.
*/
procp = (struct Process *) FindTask (0L);
lockp = procp->pr_CurrentDir;
filename[0] = 0; /* Tell DirIt() to use current dir */
}
/* Get the directory for this path, display it */
DirIt (lockp, filename);
/* Release the lock, bump our arg counter */
if (lockp != 0 && PATHNAMED != 0)
UnLock (lockp);
lockp = 0L;
cnt++;
if (cnt < argc)
WCHR("\n");
} while (cnt < argc && BREAKFLAG == 0);
CleanUp ("", 0L);
}
/* -------------------------------------------------------------------- */
/* Deallocate and close everything */
/* -------------------------------------------------------------------- */
void CleanUp (exit_msg, exit_status)
char *exit_msg;
long exit_status;
{
if (lockp && PATHNAMED)
UnLock (lockp);
if (GFibp != 0L)
FreeMem(GFibp, (long)sizeof(struct FileInfoBlock));
if (exit_status)
{
(void) asprintf (workstr, "ls: %s, Error #%ld\n", exit_msg, exit_status);
WSTR (workstr);
}
exit ((int) exit_status);
}
/* -------------------------------------------------------------------- */
void DirIt (lockp, dirname)
BPTR lockp;
char *dirname;
{
BPTR tlockp;
struct FibEntry *fibheadp;
struct FibEntry *tfibp;
char *subdir;
long strsize;
/* Try to fill FileInfoBlock, bomb if not readable for some reason */
if (!Examine (lockp, GFibp))
{
(void) asprintf (workstr, "Can't examine file or directory\n");
WSTR (workstr);
return;
}
/* Put directory header if this is a recursive listing */
if (dirname[0] && LISTALL > 0)
{
if (CONSOLE != 0)
(void)asprintf(workstr, "\23330;41m %s \2330m\n", dirname);
else
(void)asprintf(workstr, "%s\n", dirname);
WSTR(workstr);
}
/* If this is a single file list it verbosely */
if (GFibp->fib_EntryType < 0 && (DIRFILEFLAG & 2) != 0)
{
LListEntry (GFibp);
}
else
{
/* Otherwise do a directory */
/* Allocate and initialize a FibEntry head node */
if ( (fibheadp = GetDir (lockp, GFibp)) != 0L && BREAKFLAG == 0)
{
if (NOSORTFLAG == 0)
SortFibs ((long)sortkey, REVFLAG, fibheadp);
if (LONGLIST == 0)
SListDir (fibheadp);
else
LListDir (fibheadp);
if ( (LISTALL & 1) != 0)
{
tfibp = fibheadp;
do
{
if (tfibp->Fibp->fib_EntryType > 0)
{
strsize = (strlen (dirname) + strlen (tfibp->Fibp->fib_FileName) + 2);
subdir = (char *) AllocMem ((LONG)strsize, 0L);
if (strlen (dirname) != 0)
{
(void) stpcpy (subdir, dirname);
if (dirname[strlen (dirname) - 1] != ':')
(void) strcat (subdir, "/");
}
(void) strcat (subdir, tfibp->Fibp->fib_FileName);
tlockp = Lock (subdir, ACCESS_READ);
if (tlockp == 0L)
{
WSTR (subdir);
WSTR (" -- can't lock it!\n");
break;
}
else
{
WCHR ("\n"); /* Put a blank line between directories */
DirIt (tlockp, subdir);
UnLock (tlockp);
FreeMem (subdir, (LONG)strsize);
}
}
tfibp = tfibp->NextFib;
} while (tfibp != fibheadp && BREAKFLAG == 0);
}
}
/* Clean up */
FreeAllFibs (fibheadp);
}
}
/* -------------------------------------------------------------------- */
/* Allocate and fill a linked list of FileInfoBlocks */
/* -------------------------------------------------------------------- */
struct FibEntry *GetDir (lockp, fibp)
BPTR lockp;
struct FileInfoBlock *fibp;
{
long nextstat;
long tempnamlen;
struct FibEntry *tfibp;
struct FibEntry *headfib;
maxnamlen = dircount = filecount = 0L;
headfib = 0L;
do
{
TestBreak();
if (BREAKFLAG != 0)
return(headfib);
nextstat = ExNext (lockp, fibp);
if (nextstat != 0) /* We got something */
{
/* See if it matches our pattern */
if (!WILDCARD || wildmatch (fibp->fib_FileName, pattern))
{
/* Bump count of files or directories */
if (fibp->fib_EntryType > 0)
{
if ((DIRFILEFLAG & 1) != 0)
dircount++;
else
goto ALLOCFIB;
}
else
{
if ((DIRFILEFLAG & 2) != 0)
filecount++;
else
continue;
}
/* See if this is the longest filename for later use in listing */
tempnamlen = strlen (fibp->fib_FileName);
if (tempnamlen > maxnamlen)
maxnamlen = tempnamlen;
ALLOCFIB:
/* Allocate another FibEntry to put the info in */
if (headfib == 0L)
{
headfib = AllocFib();
if (headfib == 0L)
return(headfib);
headfib->NextFib = headfib;
headfib->LastFib = headfib;
*(headfib->Fibp) = *(fibp);
tfibp = headfib;
}
else
{
tfibp->NextFib = AllocFib ();
if (tfibp->NextFib == 0L)
return(0L);
/* Copy FIB contents to next entry for ExNext to work with */
*(tfibp->NextFib->Fibp) = *(fibp);
/* Link it into the list */
tfibp->NextFib->LastFib = tfibp;
tfibp = tfibp->NextFib;
tfibp->NextFib = headfib;
}
}
}
} while (nextstat);
/* Return TRUE if entries found, else print message and return FALSE */
if ( (dircount + filecount) != 0)
{
return (headfib);
}
else
{
if (WILDCARD == 0 && DIRFILEFLAG == 3)
WSTR ("Volume or directory is empty.\n");
else
WSTR ("No match.\n");
return (0L);
}
}
/* -------------------------------------------------------------------- */
/* List a FibEntry list in a compact fashion */
/* -------------------------------------------------------------------- */
void SListDir (fibheadp)
struct FibEntry *fibheadp;
{
struct FibEntry *tfibp;
long tabsize;
long maxtab;
long totrows;
long maxwinrow;
long colcnt;
long rowcnt;
long tabcnt;
long pagecnt = 1;
CursorOff (); /* Turn the cursor off since it will blink anyway */
GetWinBounds(&CurWinCols, &CurWinRows);
tfibp = fibheadp;
tabcnt = rowcnt = colcnt = 0;
tabsize = maxnamlen + 2;
if (CurWinCols < tabsize)
maxtab = 1;
else
maxtab = CurWinCols / tabsize;
maxwinrow = CurWinRows - 3;
if (maxwinrow <= 0)
maxwinrow = 1;
totrows = (dircount + filecount) / maxtab;
if ((dircount + filecount) % maxtab != 0)
totrows++;
do
{
if (tfibp->Fibp->fib_EntryType > 0)
{
if ( (DIRFILEFLAG & 1) == 0)
goto GETNEXTFIB;
else
ColorPen2 ();
}
if (tabcnt)
(void) asprintf (workstr, "\233%ldC", (long)tabcnt);
else
workstr[0] = (BYTE) 0;
(void) strcat (workstr, tfibp->Fibp->fib_FileName);
(void) strcat (workstr, "\n");
WSTR (workstr);
if (tfibp->Fibp->fib_EntryType > 0)
ResetPen ();
rowcnt++;
if (rowcnt == maxwinrow || rowcnt == totrows)
{
colcnt++; /* Start a new column */
/* Check to see if we have used the last column up and are about to run
* off the screen entirely. If so, give the user a chance to read it first.
*/
if (colcnt == maxtab && rowcnt == maxwinrow && CONSOLE != 0)
{
if (maxwinrow > 1)
{
++pagecnt; /* Advance page number count */
PagePrompt (pagecnt); /* Print it, wait for user */
}
totrows -= maxwinrow;
colcnt = tabcnt = rowcnt = 0L;
}
else /* Just move over one row and back up to the top */
{
(void) asprintf (workstr, "\233%ldA", (long)rowcnt);
WSTR (workstr);
tabcnt += tabsize;
rowcnt = 0L;
}
}
GETNEXTFIB:
tfibp = tfibp->NextFib;
} while (tfibp != fibheadp);
if (totrows - rowcnt > 0) /* Cursor down till level with */
{ /* lowest line on screen */
(void) asprintf (workstr, "\233%ldE", (long)(totrows - rowcnt));
WSTR (workstr);
}
CursorOn ();
}
/* -------------------------------------------------------------------- */
/* Reset character color to default Pen1 colors */
/* -------------------------------------------------------------------- */
void ResetPen ()
{
if (CONSOLE != 0)
WSTR ("\2330m");
}
/* -------------------------------------------------------------------- */
/* Turn the cursor on */
/* -------------------------------------------------------------------- */
void CursorOn ()
{
if (CONSOLE != 0)
WSTR ("\233 p");
}
/* -------------------------------------------------------------------- */
/* Turn the cursor off for faster text output */
/* -------------------------------------------------------------------- */
void CursorOff ()
{
if (CONSOLE != 0)
WSTR ("\2330 p");
}
/* -------------------------------------------------------------------- */
/* Make Pen2 <usually yellow/orange> the current charcter color */
/* -------------------------------------------------------------------- */
void ColorPen2 ()
{
if (CONSOLE != 0)
WSTR ("\23333m");
}
/* -------------------------------------------------------------------- */
/* Prompt the user to hit return, wait till return is hit */
/* -------------------------------------------------------------------- */
void PagePrompt (page)
long page;
{
WSTR ("\2337m -- MORE -- Press Return: \2330m");
(void) Read (In, workstr, 1L);
(void) asprintf (workstr, "\233F\233K\2334;33mPage %ld:\2330m\n", (long)page);
WSTR (workstr);
}
/* -------------------------------------------------------------------- */
/* List a directory in a verbose informative manner */
/* -------------------------------------------------------------------- */
void LListDir (fibheadp)
struct FibEntry *fibheadp;
{
long totblocks = 0L;
long totbytes = 0L;
CursorOff ();
LongList (&totblocks, &totbytes, fibheadp);
(void) asprintf (workstr, "Dirs:%-3ld Files:%-4ld Blocks:%-5ld Bytes:%-8ld\n",
(long)dircount, (long)filecount, totblocks, totbytes);
WSTR (workstr);
CursorOn ();
}
/* -------------------------------------------------------------------- */
void LongList (totblocks, totbytes, fibheadp)
long *totblocks, *totbytes;
struct FibEntry *fibheadp;
{
struct FibEntry *tfibp;
tfibp = fibheadp;
do
{
LListEntry (tfibp->Fibp);
if (tfibp->Fibp->fib_EntryType < 0)
{
*totblocks += tfibp->Fibp->fib_NumBlocks;
*totbytes += tfibp->Fibp->fib_Size;
}
tfibp = tfibp->NextFib;
} while (tfibp != fibheadp);
}
/* -------------------------------------------------------------------- */
/* Verbosely list a particular FibEntry */
/* -------------------------------------------------------------------- */
void LListEntry (fib)
struct FileInfoBlock *fib;
{
long i, pmodes;
char *cp1;
char entry[160];
pmodes = fib->fib_Protection & 0xff;
cp1 = stpcpy (entry, "chsparwed ");
for (i = 0; i < 4; i++)
{
if ((pmodes & (1 << i)) != 0)
entry[8 - i] = '-';
}
for (; i < 8; i++)
{
if ((pmodes & (1 << i)) == 0)
entry[8 - i] = '-';
}
if (fib->fib_Comment[0] == 0)
entry[0] = '-';
cp1 = stpcpy (cp1, FibFileDate (&fib->fib_Date));
if (fib->fib_EntryType > 0)
{
if ( (DIRFILEFLAG & 1) == 0)
return;
if (CONSOLE)
cp1 = stpcpy (cp1, "\23333m");
cp1 = stpcpy (cp1, " Directory ");
if (CONSOLE)
cp1 = strcat (cp1, "\2330m");
}
else
(void) asprintf (&entry[27], " %4ld %8ld ", fib->fib_NumBlocks, fib->fib_Size);
(void)strcat(entry, fib->fib_FileName);
(void)strcat(cp1, "\n");
WSTR (entry);
if (NOTEFLAG != 0 && fib->fib_Comment[0] != 0)
{
if (CONSOLE)
(void)asprintf(cp1, "\23333m/* %s */\2330m\n", fib->fib_Comment);
else
(void)asprintf(cp1, "/* %s */\n", fib->fib_Comment);
WSTR (workstr);
}
}
#ifdef NOASM
/* -------------------------------------------------------------------- */
/* Calculate date based on DateStamp structure, return a string pointer */
/* -------------------------------------------------------------------- */
char *CalcDate (fib)
struct FileInfoBlock *fib;
{
static long days[12] =
{
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
static char *months[12] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
char datestr[25];
long i, mdays;
long day, hour;
long minute, sec;
long ldays;
long year;
ldays = 1461L;
year = 78L;
day = fib->fib_Date.ds_Days;
minute = fib->fib_Date.ds_Minute;
sec = fib->fib_Date.ds_Tick / 50L;
year += (day / ldays) * 4L;
day %= ldays;
while (day)
{
mdays = 365;
if ((year & 3) == 0)
mdays++;
if (day < mdays)
break;
day -= mdays;
year++;
}
for (i = 0L, day++; i < 12; i++)
{
mdays = days[i];
if (i == 1 && (year & 3) == 0)
mdays++;
if (day <= mdays)
break;
day -= mdays;
}
hour = minute / 60;
minute -= hour * 60;
(void) asprintf (datestr, "%02ld-%s-%02ld %02ld:%02ld:%02ld ", day, (long)months[i], year, hour, minute, sec);
return (datestr);
}
#endif
/* -------------------------------------------------------------------- */
/* Use AmigaDos to put a string on the stdout */
/* -------------------------------------------------------------------- */
void WSTR (tstring)
char *tstring;
{
(void) Write (Out, tstring, (long) strlen (tstring));
}
/* -------------------------------------------------------------------- */
/* Use AmigaDos to put a character on the stdout */
/* -------------------------------------------------------------------- */
void WCHR (ch)
char *ch;
{
(void) Write (Out, ch, 1L);
}
/* -------------------------------------------------------------------- */
/* Check to see if the user hit ^C */
/* -------------------------------------------------------------------- */
void TestBreak ()
{
unsigned long oldsig;
oldsig = SetSignal (0L, SIGBREAKF_CTRL_C);
if ( (oldsig & SIGBREAKF_CTRL_C) != 0L)
{
WSTR ("\2330m\233 p**BREAK\n");
BREAKFLAG = 1;
}
}
/* -------------------------------------------------------------------- */
/* Explain how to use */
/* -------------------------------------------------------------------- */
void Usage ()
{
WSTR (Author);
WSTR (usage);
WSTR (" c > Show comments\n");
WSTR (" d > Dirs only\n");
WSTR (" f > Files only\n");
WSTR (" l > Long listing\n");
WSTR (" n > No sort\n");
WSTR (" r > Reverse sort\n");
WSTR (" s > Sort by size\n");
WSTR (" t > Sort by date\n");
WSTR (" R > Recursive listing\n");
CleanUp ("", 0L);
}
/* -------------------------------------------------------------------- */
/* Allocate a FibEntry structure and associated FileInfoBlock */
/* -------------------------------------------------------------------- */
struct FibEntry *AllocFib ()
{
struct FibEntry *tfibp;
tfibp = (struct FibEntry *) AllocMem \
((long)( sizeof (struct FibEntry) + sizeof(struct FileInfoBlock) ), 0L);
if (tfibp != 0L)
{
tfibp->Fibp = (struct FileInfoBlock *)((ULONG)tfibp + sizeof(struct FibEntry));
}
else
BREAKFLAG = 1;
return (tfibp);
}
/* -------------------------------------------------------------------- */
/* Free up memory allocated to a linked list of FibEntrys */
/* -------------------------------------------------------------------- */
void FreeAllFibs (fibheadp)
struct FibEntry *fibheadp;
{
struct FibEntry *fibp;
struct FibEntry *tfibp;
if (fibheadp != 0)
{
fibp = fibheadp;
do
{
tfibp = fibp->NextFib;
FreeFib (fibp);
fibp = tfibp;
} while (tfibp != fibheadp);
}
}
/* -------------------------------------------------------------------- */
/* Deallocate a single FibEntry structure */
/* -------------------------------------------------------------------- */
void FreeFib (fibp)
struct FibEntry *fibp;
{
if (fibp != 0L)
FreeMem (fibp, (long)(sizeof (struct FibEntry) + sizeof(struct FileInfoBlock)));
}
SHAR_EOF
cat << \SHAR_EOF > ls.doc
LS.C -- an "improved" directory listing utility to replace the
AmigaDOS DIR and LIST commands.
V1.0 August 1986 Written from scratch by Justin V. McCormick.
V2.0 November 1988 Revised for Lattice 5.0 and made 1.3 compatible.
Notice:
This program is placed in the public domain with the understanding
that the author makes no claims or guarantees with regard to its
suitability for any given application, and that the author assumes no
responsibility for damages incurred by its usage. Any resemblance
of this program to any other program, either living or dead, is
purely coincidental.
Feel free to steal this code and make millions of dollars from its sale
or commercial use, but please give credit where credit is due.
Synopsis:
Features adaptive columnar listing, versatile sort options,
UNIX-style pattern matching, recursive subdirectory listing, etc!
Usage:
ls [options] [path1] [path2] ...
Options:
-? Help!
-c Show file comment info, -c implies -l
-d Show directory names only
-f Show filenames only
-l Long verbose listing showing filesizes and dates
-n No sort, just spit them out in the order ExNext() returns
-r Reverse sort direction
-s Sorted by size smallest to largest
-t Sorted by date oldest to newest
-R Recursive descent of subdirectories
All arguments are optional. Default is to give short columnar listing,
sorted alphabetically, using the current directory. Alphabetizing is case
insensitive.
Patterns may be matched in the given names, using the UNIX-style '*'
to wildcard any number of characters, and '?' to wildcard a single
character. If you need to specify a pathname with spaces in it like
"Wombat Soup", you need to put quotes around it. LS can process up to 30
separate pathname patterns in one command line.
Bugs:
Redirecting the shortlist output to PRT: gives undesirable results,
since I am using relative cursor positioning commands to format the
screen output. I thought about using an array to store a virtual
screen, but my primary goals were to keep the size down and display
speed at a maxiumum. Also, LS cannot pattern match devices (like "dh*:")
or support multiple levels of pattern matching (like "dh0:?/L*.info").
This would involve another level of recursion and groking the Device List.
Changes From 1.0 to 2.0:
o Source code prototyped, linted, traced, optimized, tweaked, etc.
o Made resident ("pseudo-pure") by linking with cres.o from LC 5.0.
o High-volume routines recoded in assembly (lssup.a).
o Now handles multiple paths/files on a command line, up to 30.
o New sort flags, including no sort.
o Enhanced wildcards, understands complex *.?*.* expressions now.
o More efficient ExNext() performance, less ram used for recursion.
o SIGBREAKF_CTRL_C signal (Ctrl-C) cleanly aborts at any point now.
o Command line parser handles quoted pathnames now (LC 5.0 benefit).
o Short listing finally auto-adjusts to new console window sizes!
o Pen color escape codes bypassed when redirecting long output.
o Sorting by size or date is also subsorted alphabetically now.
o Long listing shows new 1.3 file attributes, plus comment indicator.
o File dates are now in international format, YY-MM-DD.
o Fixed listings with files datestamped after 99-12-31 (overflow).
o Fixed listings with files datestamped before 78-01-01 (time < 0).
Don't send me money for this one! Its a Christmas present 8-)
However, if you find any bugs I'd like to hear about them!
Justin V. McCormick
8330 E. Quincy Ave., C-312
Denver, CO 80237
Home: 303-290-8429
Work: 303-825-4144
SHAR_EOF
cat << \SHAR_EOF > ls.h
#include <dos.h>
#include <libraries/dosextens.h>
/*lint -save */
/*lint -library */
#include <proto/exec.h>
#include <proto/dos.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*lint -restore */
extern int tolower (char);
/* Prevent Lint from complaining about ANSI prototype extensions */
#ifdef _lint
#define __asm
#define __stdargs
#define R_D0
#define R_D1
#define R_A0
#else
#define R_D0 register __d0
#define R_D1 register __d1
#define R_A0 register __a0
#endif
#define MEMF_PUBLIC (1L<<0)
#define MEMF_CHIP (1L<<1)
#define MEMF_FAST (1L<<2)
#define MEMF_CLEAR (1L<<16)
SHAR_EOF
cat << \SHAR_EOF > ls.lnk
DEFINE @_main = @_tinymain
DEFINE @XCEXIT = xXCEXIT
DEFINE @chkabort = xchkabort
DEFINE @write = xchkabort
DEFINE @_dclose = xchkabort
SC SD ND
SHAR_EOF
cat << \SHAR_EOF > lssup.a
* --------------------------------------------------------------------- *
* LSSUP.A - Assembly support routines for ls.c *
* Copyright (c) 1988 by Justin V. McCormick. All Rights Reserved. *
* --------------------------------------------------------------------- *
IDNT "lssup.a"
include "asm:inc/macros.i"
; Assembler options for CAPE
BASEREG B
SMALLOBJ
OPTIMON
ADDSYM
DEBUG
; Equates
fib_FileName equ $8
fib_Size equ $7C
fib_NumBlocks equ $80
fib_DateStamp equ $84
ds_Days equ $0
ds_Minute equ $4
ds_Tick equ $8
_LVOAddPort equ $FFFFFE9E
_LVOAllocMem equ $FFFFFF3A
_LVOAllocSignal equ $FFFFFEB6
_LVODebug equ $FFFFFF8E
_LVOFindTask equ $FFFFFEDA
_LVOFreeMem equ $FFFFFF2E
_LVOFreeSignal equ $FFFFFEB0
_LVOGetMsg equ $FFFFFE8C
_LVOPutMsg equ $FFFFFE92
_LVORawDoFmt equ $FFFFFDF6
_LVORemPort equ $FFFFFE98
_LVORead equ $FFFFFFD6
_LVOWaitPort equ $FFFFFE80
_LVOWrite equ $FFFFFFD0
pr_ConsoleTask EQU $A4
MEMF_CLEAR EQU $10000
MEMF_PUBLIC EQU $1
sp_Msg EQU $0
sp_Pkt EQU $14
sp_SIZEOF EQU $44
dp_Link EQU $0
dp_Port EQU $4
dp_Arg1 EQU $14
dp_Type EQU $8
ACTION_SCREEN_MODE EQU $3E2
LN_NAME EQU $A
LN_PRI EQU $9
LN_TYPE EQU $8
MP_FLAGS EQU $E
MP_MSGLIST EQU $14
MP_SIGBIT EQU $F
MP_SIGTASK EQU $10
MP_SIZE EQU $22
NT_MSGPORT EQU $4
PA_SIGNAL EQU $0
* External constants
XREF _DOSBase
XREF _Out
XREF _In
* --------------------------------------------------------------------- *
SECTION lssup,CODE
* ------------------------------------------------------------------------- *
* void asprintf(wstr, formatstring, args)
* char *wstr;
* char *formatstring;
* char **args;
*
* Synopsis: Given formatstring and args to format, formats output to wstr.
* Similar to sprintf(), except doesn't handle floats.
* ------------------------------------------------------------------------- *
XDEF _asprintf
_asprintf:
link a5,#0
movem.l d0-d2/a0-a3,-(sp) ;Save everything we might clobber
* Call format function to convert fmtstring and args to buffer on the stack
movea.l 12(a5),a0 ;Grab format string
lea 16(a5),a1 ;Grab EA of arguments
lea kput1,a2 ;Grab EA of output subroutine
movea.l 8(a5),a3 ;Grab EA of dest workspace
SYS RawDoFmt,4 ;Format it into workspace
movem.l (sp)+,d0-d2/a0-a3 ;Restore registers
unlk a5 ;And stack frame
rts
* ------------------------------------------------------------------------- *
* RawDoFmt() output routine for xprintf, called for each formatted char.
* Takes byte in d0 and puts in buffer pointed to by a3, then increments a3.
* ------------------------------------------------------------------------- *
XDEF kput1
kput1:
move.b d0,(a3)+
rts
* --------------------------------------------------------------------- *
* void GetWinBounds(width, height)
* long *width, *height;
*
* Find current console window, determine width and height
* in terms of current font, update width and height VPARMS passed.
* --------------------------------------------------------------------- *
rpstr equ -32
rpport equ -12
packet equ -8
conid equ -4
width equ 8
height equ 12
XDEF _GetWinBounds
_GetWinBounds:
link a5,#-32
movem.l d2-d4/a2,-(sp)
suba.l a1,a1
SYS FindTask,4 ;d0 = FindTask(0L), our process
movea.l d0,a0 ;Transfer to address reg
move.l pr_ConsoleTask(a0),conid(a5) ;Save proc->pr_ConsoleTask
moveq #0,d4 ;Clear our success status register
moveq #0,d0
movea.l d0,a0
bsr.w CreatePort
move.l d0,rpport(a5) ;rpport = CreatePort(0L, 0L)
beq.w gwbdone ;Oops, no signals or ram available!
move.l #MEMF_PUBLIC+MEMF_CLEAR,d1
moveq #sp_SIZEOF,d0
SYS AllocMem
move.l d0,packet(a5) ;packet = AllocMem(sizeof(*packet),MEMF_PUBLIC|MEMF_CLEAR)
beq.w gwbfreeport ;Oops, no ram, free up port
* Okay, we got our process id, reply port, and packet
* Now toggle the console into raw mode
movea.l rpport(a5),a2
movea.l d0,a1
movea.l conid(a5),a0
moveq #1,d0
bsr.w SetConsoleType ;SetConsoleType(1L, conid, packet, rpport)
* Request a window bounds report
moveq #4,d3
lea gwbrstr(a4),a0
move.l a0,d2
move.l _Out(a4),d1
SYS Write,_DOSBase(a4) ;Write(Output(), "\2330 q", 4L);
cmpi.l #$0004,d0 ;Did the console choke on it?
bne.w gwbsetcook ;hmmm, see if we can back out gracefully
* Read the report string into stack buffer
moveq #16,d3 ;Don't let it get longer than 16 characters
lea rpstr(a5),a0 ;Point to input string area
move.l a0,d2
move.l _In(a4),d1
SYS Read ;Read(Input(), rpstr, 16L)
move.l d0,d4 ;Save read length while we close shop
* Turn the console back to cooked mode pronto to avoid cursor blink
gwbsetcook:
movea.l rpport(a5),a2
movea.l packet(a5),a1
movea.l conid(a5),a0
moveq #0,d0
bsr.w SetConsoleType ;SetConsoleType(0L, conid, packet, rpport)
* Release resources we borrowed
gwbfreepack:
move.l packet(a5),d0 ;Did we allocate a packet?
beq.b gwbfreeport ;nay, check for port to free
movea.l d0,a1
moveq #sp_SIZEOF,d0
SYS FreeMem ;Else FreeMem(packet, sizeof(*packet))
gwbfreeport:
move.l rpport(a5),d0 ;if (rpport)...
beq.w gwbdone ;nope
bsr.w DeletePort ;Else DeletePort(rpport)
* Finally, sanity check window bounds report string
* d4 = length of report string according to Read()
cmpi.l #9,d4 ;Less than 8 characters returned?
ble.w gwbdone ;hmmm, phonky bounds report from DOS?
lea rpstr(a5),a2 ;a2 = rpstr
cmpi.b #';',4(a2) ;Matches a typical report template?
bne.w gwbdone ;nope, got some weird junk back?
cmpi.b #'r',-1(a2,d4.w) ;Last byte is 'r' for report?
bne.w gwbdone ;Nope, message fubar!
* Parse the height and width variables from the field now
* Our report format looks like this in hex:
* 9b 31 3b 31 3b y2 y1 3b x2 x1 20 72
* Or in ascii:
* <0x9b>1;1;20;77 r
* Which would indicate a width of 77 cols and a height of 20 rows for
* the current console device
*
* REGS: a2 points to beginning of 'r' terminated string
lea 5(a2),a2 ;Point to first char of Y size
moveq #0,d1 ;Clear out work reg
* Convert ascii rows value to LONG, update host data
move.b (a2)+,d1 ;Grab a Y
subi.w #'0',d1 ;Less ascii offset
cmpi.b #';',(a2) ;Any more Y digits?
beq.b 1$ ;Nope
mulu #10,d1 ;Else shift by 10
add.b (a2)+,d1 ;Add least significant Y digit
subi.b #'0',d1 ;Less ascii offset
cmpi.b #';',(a2) ;Any more Y digits?
beq.b 1$ ;Nope
mulu #$000a,d1 ;Else shift by 10
add.b (a2)+,d1 ;Add least significant Y digit
subi.b #'0',d1 ;Less ascii offset
;We'll assume screen height < 999 rows
1$
* Convert ascii columns value to LONG, update host data
addq.w #1,a2 ;Move past the ';' separator
moveq #0,d2 ;Zap work reg
move.b (a2)+,d2 ;Grab msd of X
cmpi.b #' ',d2 ;Premature end?
beq.w gwbdone ;Huh, must be garbage - don't update VPARMS
cmpi.b #';',d2 ;Also a possible error
beq.w gwbdone
cmpi.b #'r',d2 ;And what about this?
beq.w gwbdone
subi.b #'0',d2 ;Okay, adjust ascii offset
cmpi.b #' ',(a2) ;Hit end of report?
beq.b 2$ ;Yep
mulu #$000a,d2 ;Else shift by 10
add.b (a2)+,d2 ;Add next digit
subi.b #'0',d2 ;Ascii adjust
cmpi.b #' ',(a2) ;Hit end of report?
beq.b 2$ ;Yep
mulu #$000a,d2 ;Else shift by 10
add.b (a2),d2 ;Add next digit
subi.b #'0',d2 ;Ascii adjust
2$
* Finally, update parameters by reference
movea.l height(a5),a0 ;Grab height VPARM
move.l d1,(a0) ;*height = d1
movea.l width(a5),a0 ;Grab width VPARM
move.l d2,(a0) ;*width = d2
gwbdone:
movem.l (sp)+,d2-d4/a2
unlk a5
rts
* --------------------------------------------------------------------- *
* __asm void SetConsoleType(flag, id, packet, port)
* register __d0 long flag;
* register __a0 struct Process *id;
* register __a1 struct StandardPacket *packet;
* register __a2 struct MsgPort *port;
*
* Flag = 1L -- Raw mode
* = 0L -- Cooked mode
* --------------------------------------------------------------------- *
XDEF SetConsoleType
SetConsoleType:
movem.l a3/a5,-(sp)
movea.l a0,a3 ;Copy process pointer
movea.l a1,a5 ;Copy packet pointer
lea sp_Pkt(a5),a0 ;a0 = &packet->sp_Pkt
move.l a0,sp_Msg+LN_NAME(a5) ;p->sp_Msg.mn_Node.ln_Name = &p->sp_Pkt
lea sp_Msg(a5),a0 ;a0 = &packet->sp_Msg
move.l a0,sp_Pkt+dp_Link(a5) ;p->sp_Pkt.dp_Link = &p->sp_Msg
move.l a2,sp_Pkt+dp_Port(a5) ;p->sp_Pkt.dp_Port = replyport
move.l #ACTION_SCREEN_MODE,sp_Pkt+dp_Type(a5) ;Set function
tst.w d0 ;On or Off?
beq.w 1$
move.l #-1,sp_Pkt+dp_Arg1(a5) ;RAW ON
bra.b 2$
1$
clr.l sp_Pkt+dp_Arg1(a5) ;RAW OFF
2$
movea.l a3,a0
movea.l a5,a1
SYS PutMsg,4 ;PutMsg(proc, packet)
movea.l a2,a0
SYS WaitPort ;WaitPort(port)
movea.l a2,a0
SYS GetMsg ;(void)GetMsg(port)
movem.l (sp)+,a3/a5
rts
* ------------------------------------------------------------------------- *
* struct MsgPort *CreatePort(name, pri) (a0/d0)
* ------------------------------------------------------------------------- *
XDEF CreatePort
CreatePort:
movem.l d5/d7/a2/a5,-(sp)
move.l a0,a5 ;Save Name
move.l d0,d5 ;Save Pri
* Allocate a free signal, crap out if we can't
moveq #-1,d0
SYS AllocSignal,4
cmp.l #-1,d0 ;Did we get a signal?
bne.b cpgotsig ;Yep
moveq #0,d0 ;Otherwise return NULL
bra.w cpdone
cpgotsig:
move.l d0,d7 ;Save our signal
* Allocate memory for MsgPort
moveq.l #MP_SIZE,d0 ;Size of MsgPort
move.l #MEMF_PUBLIC!MEMF_CLEAR,d1 ;Type of memory
SYS AllocMem ;Allocate it
tst.l d0 ;Did we get it?
bne.b cpgotport ;Yep
move.l d7,d0 ;Otherwise crap out, free signal
SYS FreeSignal
moveq #0,d0 ;Return NULL
bra.w cpdone
cpgotport:
move.l d0,a2 ;This is our new port!
move.l a5,LN_NAME(a2) ;port->mp_Node.ln_Name = name
move.b d5,LN_PRI(a2) ;port->mp_Node.ln_Pri = priority
move.b #NT_MSGPORT,LN_TYPE(a2) ;port->mp_Node.ln_Type = NT_MSGPORT
move.b #PA_SIGNAL,MP_FLAGS(a2) ;port->mp_Flags = PA_SIGNAL
move.b d7,MP_SIGBIT(a2) ;port->mp_SIGBIT = sigBit
suba.l a1,a1
SYS FindTask
move.l d0,MP_SIGTASK(a2) ;port->mp_SIGTASK = FindTask(0L)
cmpa.l #0,a5 ;Is this a new name?
beq.b cpnoname ;Nope, add it to the msg list
movea.l a2,a1
SYS AddPort ;Otherwise add this port
move.l a2,d0 ;Return port pointer
bra.b cpdone
cpnoname:
* Initialized New List head
lea MP_MSGLIST(a2),a0 ;a0 = &port->mp_MsgList
move.l a0,(a0) ;list->lh_Head = list
addq.l #4,(a0) ;list->lh_Head += 4L
clr.l 4(a0) ;list->lh_Tail = 0L
move.l a0,8(a0) ;list->lh_TailPred = list
move.l a2,d0 ;Return port pointer
cpdone:
movem.l (sp)+,d5/d7/a2/a5
rts
* ------------------------------------------------------------------------- *
* DeletePort(port)(d0)
* ------------------------------------------------------------------------- *
XDEF DeletePort
DeletePort:
move.l a5,-(sp)
move.l d0,a5
tst.l LN_NAME(a5) ;Is there a name?
beq.s dpnoname
move.l d0,a1
SYS RemPort,4 ;RemPort(port)
dpnoname:
move.b #$ff,LN_TYPE(a5) ;port->mp_Node.ln_Type = 0xff
move.l #-1,MP_MSGLIST(a5) ;port->mp_MsgList.lh_Head = -1L
moveq #0,d0
move.b MP_SIGBIT(a5),d0 ;d0 = port->mp_SigBit
SYS FreeSignal,4 ;FreeSignal(d0)
moveq #MP_SIZE,d0
move.l a5,a1
SYS FreeMem ;FreeMem(port, sizeof(*port))
move.l (sp)+,a5
rts
* ------------------------------------------------------------------------
* char *FibFileDate(fib_date)
* register struct DateStamp *fib_date;
*
* Calculate date based on DateStamp structure and return a pointer
* to the formatted date string.
* ------------------------------------------------------------------------
XDEF _FibFileDate
_FibFileDate:
link a5,#0
movem.l d3-d7/a4,-(sp)
movea.l 8(a5),a1 ;Grab datestamp pointer
moveq #78,d7 ;Initial year = 1978
move.l (a1),d5 ;days = fib_date->ds_Days
blt ffdbaddate ;Hey! you can't be negative! Invalid date...
* Determine what year it is
divu #1461,d5
move.l d5,d0 ;Stash it
ext.l d5
lsl.l #2,d5
add.l d5,d7 ;year += (days / 1461) * 4
* Count how many months into that year
ffdgetmo:
swap d0 ;days %= 1461
move.w d0,d5
1$ tst.w d5 ;Out of days yet?
beq 3$ ;Yep, done here
move.w #365,d6 ;Else month_days = 365
move.w d7,d0 ;Grab year
andi.w #3,d0 ;if (year & 3) == 0 Leap year?
bne 2$ ;Nope
addq.w #1,d6 ;Otherwise bump month_days
2$ cmp.w d6,d5 ;is day < month_days?
blt 3$ ;yep, done here
sub.w d6,d5 ;otherwise day -= month_days
addq.l #1,d7 ; year++
bra 1$
3$
* Count how many days into that month of that year
ffdgetday:
;for (i = 0, day++; i < 12; i++)
moveq #0,d4 ;current month = 0
moveq #0,d6 ;Zap hinybs
addq.w #1,d5
lea _dayspermonth(a4),a0
1$
move.b 0(a0,d4.w),d6 ;month_days = dayspermonth[i]
cmpi.w #1,d4 ;if (i == 1 && (year & 3) == 0)
bne 2$
move.w d7,d0
andi.w #3,d0
bne 2$
addq.w #1,d6 ;month_days++
2$ cmp.w d6,d5 ;if (day <= month_days)
ble 4$ ;Break out, found the right month
sub.w d6,d5 ;Else, day -= month_days
addq.w #1,d4 ;i++
3$ cmpi.w #12,d4 ;Done all months yet?
blt 1$ ;Nope
4$
ffdprint:
1$ cmpi.l #99,d7 ;while (year >= 100)
ble 2$
subi.l #100,d7 ;year -= 100
bra 1$
2$
;asprintf(datestr, "%02d-%02d-%02d %02d:%02d:%02d", i + 1, day, year, hour, min, sec)
move.l 8(a1),d0 ;sec = fib_date->ds_Tick / 50;
divu #50,d0
move.w d0,-(sp) ;Push secs
moveq #0,d0 ;Zap reg
move.w 6(a1),d0 ;min = fib_date->ds_Minute
move.w d0,d1 ;Clone it
divu #60,d0
move.w d0,d3 ;hour = min / 60
mulu #60,d0
sub.w d0,d1 ;min -= hour * 60
move.w d1,-(sp) ;Push mins
move.w d3,-(sp) ;Push hours
addq.w #1,d4 ;Push day of month (offset by 1!)
move.w d5,-(sp) ;Push month
move.w d4,-(sp)
move.w d7,-(sp) ;Push year
pea _datepat(a4) ;Push the format pattern
pea _datestr(a4) ;Push destination buffer
jsr _asprintf
lea 20(sp),sp
lea _datestr(a4),a0
move.l a0,d0 ;return((char *)&datestr[0])
ffddone:
movem.l (sp)+,d3-d7/a4
unlk a5
rts
ffdbaddate:
lea _baddatestr(a4),a0 ;return (" <Invalid Date> ");
move.l a0,d0
bra ffddone
*----------------------------------------------------------------------
* LONG iswild(name)
* char *name;
*
* Search a string for wild characters, return 1 if found
*----------------------------------------------------------------------
XDEF _iswild
_iswild:
movea.l 4(sp),a0 ;Grab string pointer
moveq #0,d0 ;Clear out our character register
ischk1:
move.b (a0)+,d0 ;Grab a char
beq iwdone ;Might be end of string?
cmpi.b #'*',d0 ;Is it *?
beq iswdone ;yep, is wild
cmpi.b #'?',d0 ;Is it a qmark
bne ischk1 ;Nope, check next character
iswdone:
moveq #1,d0
iwdone:
rts
* ------------------------------------------------------------------------
; Compare a wild card name with a normal name
; LONG wildmatch (name, wild)
; char *name, *wild;
* ------------------------------------------------------------------------
XDEF _wildmatch
_wildmatch:
link a5,#-64
movem.l d3/a2-a3,-(sp)
movea.l 8(a5),a2 ;Grab name
movea.l 12(a5),a3 ;Grab pattern
lea -64(a5),a0 ;back[0][0]
lea -60(a5),a1 ;back[0][1]
moveq #0,d3 ;bi = 0
wmloop1:
tst.b (a2) ;End of name?
bne wmnoteon
tst.b (a3) ;End of pattern?
beq wmmatched ;Yep, we matched
wmnoteon:
cmpi.b #'*',(a3) ;Is it a splat?
bne wmnotstar ;Nope, maybe '?'
cmpi.w #64,d3 ;Have we hit max expression depth?
beq wmnomatch ;Yep, ran out of room in recursion table
;back[bi][0] = w
move.l a3,0(a0,d3.w) ;Stash pointer to this '*' in table
;back[bi][1] = n
move.l a2,0(a1,d3.w)
addq.w #8,d3 ;++bi
addq.w #1,a3 ;++w
bra wmloop1 ;Check next
wmgoback:
subq.w #8,d3 ;--bi
move.l a0,d0
wmback1:
tst.w d3 ;while (bi >= 0 && *back[bi][1] == '\x0')
blt wmbacked
movea.l 0(a1,d3.l),a0
tst.b (a0)
bne wmbacked
subq.w #8,d3 ;--bi
bra wmback1
wmbacked:
tst.w d3 ;if (bi < 0)
blt wmnomatch ;return (0)
movea.l d0,a0
movea.l 0(a0,d3.w),a3 ;w = back[bi][0] + 1
addq.w #1,a3
addq.l #1,0(a1,d3.w)
movea.l 0(a1,d3.l),a2 ;n = ++back[bi][1]
addq.w #8,d3 ;++bi
bra wmloop1
wmnotstar:
cmpi.b #'?',(a3) ;Is it '?'
bne wmnotqmark
tst.b (a2) ;Reached end of string?
bne wmincpoint ;Nope, move on to next char
tst.w d3 ;Are we at top level of expression?
beq wmnomatch ;Yep, expression didn't match
bra wmgoback ;Otherwise pop a level and try to match
wmnotqmark:
move.b (a2),d0 ;Grab a char from bstr
cmpi.b #$40,d0 ;less than @ character?
bls 1$ ;Yep
cmpi.b #$5a,d0 ;Greater than Z?
bhi 1$ ;Yep
addi.b #$20,d0
1$
move.b (a3),d1 ;Grab a char from bstr
cmpi.b #$40,d1 ;less than @ character?
bls 2$ ;Yep
cmpi.b #$5a,d1 ;Greater than Z?
bhi 2$ ;Yep
addi.b #$20,d1
2$
cmp.b d0,d1 ;*n = *w?
beq wmincpoint ;Yep, move on past
tst.w d3 ;Are we at top expression level?
beq wmnomatch ;Yep, they didn't match
bra wmgoback ;Nope, process next part
wmincpoint:
tst.b (a2) ;Done with name?
beq wmnamend ;Yep
addq.w #1,a2 ;Otherwise increment name pointer
wmnamend:
tst.b (a3) ;End of pattern?
beq wmmatched ;Yep, we matched
addq.w #1,a3 ;Otherwise inc wild pointer, match next char
bra wmloop1
wmmatched:
moveq #1,d0
bra wmdone
wmnomatch:
moveq #0,d0
wmdone:
movem.l (sp)+,d3/a2-a3
unlk a5
rts
* --------------------------------------------------------------------- *
* void SortFibs (keytype, direction, fibheadp)
* d0 d1 a0
* int keytype;
* struct FibEntry *fibheadp;
*
* Selection sort a linked list of FibEntrys based on a keycode *
* --------------------------------------------------------------------- *
XDEF _SortFibs
_SortFibs:
link a5,#0
movem.l d2-d4/a2-a3/a6,-(sp)
move.l d0,d2 ;Save keytype
move.l d1,d4 ;Save direction of sort
movea.l a0,d3 ;Save fibheadp
movea.l a0,a2 ;a2 = a0 = i
sfILoop:
cmp.l (a2),d3 ;i->NextFib != fibheadp?
beq sfdone ;Nope, wrapped around to start
movea.l a2,a6 ;k = i
movea.l (a2),a3 ;j = i->NextFib
sfJLoop:
cmp.l a3,d3 ;j != fibheadp?
beq sfJdone ;Nope compared them all, see if swapped any
movea.l 8(a6),a0 ;a0 = k->Fibp
movea.l 8(a3),a1 ;a1 = j->Fibp
move.l d2,d0 ;d0 = keytype
jsr _CompFibs ;d0 = CompFibs(keytype, k->Fibp, j->Fibp)
tst.w d4 ;Reverse sort?
beq 1$ ;Nope
bchg.l #0,d0 ;Else reverse sense of return
1$
tst.l d0 ;Return != 0?
beq sfNextJ ;Nope, these two are in order
movea.l a3,a6 ;else k = j, this is new swap
sfNextJ:
movea.l (a3),a3 ;j = j->NextFib
bra sfJLoop ;Check bounds
sfJdone:
cmpa.l a6,a2 ;k != i, did we swap?
beq sfNextI ;Nope, i was in correct position already
move.l 8(a6),d0
move.l 8(a2),8(a6)
move.l d0,8(a2) ;Else SwapFibs (k, i)
sfNextI:
movea.l (a2),a2 ;i = i->NextFib
bra sfILoop ;Check bounds
sfdone:
movem.l (sp)+,d2-d4/a2-a3/a6
unlk a5
rts
* --------------------------------------------------------------------- *
* int CompFibs (keytype, a, b)
* d0 a0 a1
* int keytype;
* struct FileInfoBlock *a, *b;
*
* Used by SortFibs to determine precedence of Fibs.
* --------------------------------------------------------------------- *
XDEF _CompFibs
_CompFibs:
tst.w d0 ;Alphabetize?
bne cfnalpha ;Nope
* Compare lexigraphically, ignoring case differences
cfalpha:
lea fib_FileName(a0),a0 ;a = &Fipb->fib_FileName
lea fib_FileName(a1),a1 ;b = &Fipb->fib_FileName
; for(; *a && tolower(*a) == tolower(*b); a++, b++);
lccstart:
tst.b (a0) ;Is there a char here at source?
beq lcceostr ;Nope, fell off the end
move.b (a1)+,d1 ;Grab a char from bstr
cmpi.b #$40,d1 ;less than @ character?
bls 1$ ;Yep
cmpi.b #$5a,d1 ;Greater than Z?
bhi 1$ ;Yep
addi.b #$20,d1
1$
move.b (a0)+,d0 ;Grab a char from astr
cmpi.b #$40,d0 ;less than @ character?
bls 2$ ;Yep
cmpi.b #$5a,d0 ;Greater than Z?
bhi 2$ ;Yep
addi.b #$20,d0
2$
cmp.b d0,d1 ;are they the same?
beq lccstart ;Yep, compare next pair of chars
lcceostr:
sub.b d1,d0 ;return(tolower(*astr) - tolower(*bstr))
bgt cftrue ; > 0?, return TRUE
bra cffalse ;Else return FALSE
cfnalpha:
subq.w #1,d0 ;Size?
bne cfnsize ;Nope
* Compare fib_Sizes
move.l fib_Size(a1),d0 ;d0 = bfib->fib_Size
cmp.l fib_Size(a0),d0 ;a->fib_Size > b->fib_Size?
blt cftrue ;Yep, return TRUE
bgt cffalse ;<, return FALSE
bra cfalpha ;Else it's a tie, alphabetize
cfnsize:
subq.w #1,d0 ;Time?
bne cffalse ;Nope, an error!
* Compare fib_DateStamps
lea fib_DateStamp(a0),a0 ;a = &afib->fib_DateStamp
lea fib_DateStamp(a1),a1 ;b = &bfib->fib_DateStamp
move.l ds_Days(a1),d0 ;d0 = bdate->ds_Days
cmp.l ds_Days(a0),d0 ;a->ds_Days > b->ds_Days?
blt cftrue ;Yep, a is older
bgt cffalse ;Else if a < b, b is older
;Else they are the same day, check min/tick
move.l ds_Minute(a0),d0
sub.l ds_Minute(a1),d0 ;d0 = amin - bmin
muls #3000,d0 ; * 3000
add.l ds_Tick(a0),d0
sub.l ds_Tick(a1),d0 ; + atick - btick
bgt cftrue ;Hey, a > b
blt cffalse ;a < b, return false
bra cfalpha ;Else its the same date, alphabetize
cftrue:
moveq #1,d0
rts
cffalse:
moveq #0,d0
rts
* --------------------------------------------------------------------- *
SECTION __MERGED,DATA
* --------------------------------------------------------------------- *
XDEF _dayspermonth
_dayspermonth:
dc.b 31,28,31,30,31,30,31,31,30,31,30,31
XDEF _datepat
_datepat:
dc.b '%02d-%02d-%02d %02d:%02d:%02d',0
CNOP 0,2
XDEF _baddatestr
_baddatestr:
dc.b '00-00-00 00:00:00',0
CNOP 0,2
XDEF gwbrstr
gwbrstr:
dc.b $9b,'0 q'
* --------------------------------------------------------------------- *
SECTION __MERGED,BSS
* --------------------------------------------------------------------- *
XDEF _datestr
_datestr:
ds.b 40
* --------------------------------------------------------------------- *
END
* --------------------------------------------------------------------- *
SHAR_EOF
cat << \SHAR_EOF > makefile
# -------------------------------------------
# LS 2.0 lmkfile by Justin V. McCormick 88/11/27
# -------------------------------------------
OBJS = c2.o ls.o lssup.o
DEST = lcs
ASM = casm
ASFLAGS = -cv
AINC = ainc:
LC = lc
LC1 = lc1
LC2 = lc2
LCFLAGS = -ccfmsu -d2 -rr -v
LINK = blink
LIBS = lib:lcr.lib
LNMAP = F H L S X PLAIN WIDTH 84 HEIGHT 0 SWIDTH 20
.a.o:
$(ASM) -a $*.a -o$*.o -i$(AINC) $(ASFLAGS)
.c.o:
$(LC) $(LCFLAGS) $*
$(DEST): $(OBJS)
$(LINK) $(OBJS) to $(DEST) LIB $(LIBS) WITH $(DEST).lnk MAP $(DEST).map $(LNMAP)
SHAR_EOF
# End of shell archive
exit 0
--
Bob Page, U of Lowell CS Dept. page@swan.ulowell.edu ulowell!page
Have five nice days.